import type { SceneViewerConfig } from './SceneViewer';

export function loadScript(url?: string, type?: string, text?: string): Promise<void> {
  return new Promise<void>((resolve, reject) => {
    let script = document.querySelector(`script[src='${url}']`) as HTMLScriptElement;
    if (script) {
      resolve();
    } else {
      script = document.createElement('script');
      script.type = type ?? 'text/javascript';
      if (text) {
        script.text = text;
      }

      script.onload = () => {
        resolve();
      };
      script.onerror = (error) => {
        reject(error);
      };
      if (url) {
        script.src = url;
      }
      document.body.appendChild(script);
      if (!url) {
        resolve();
      }
    }
  });
}

export function isReady(): Promise<void> {
  if (window['System']) {
    return Promise.resolve();
  }

  return new Promise((resolve, reject) => {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    let timeoutHandler: any = 0;
    const interval = setInterval(() => {
      if (window['System']) {
        clearInterval(interval);
        clearTimeout(timeoutHandler);
        resolve();
      }
    }, 100);

    timeoutHandler = setTimeout(() => {
      clearInterval(interval);
      clearTimeout(timeoutHandler);
      reject(new Error('SystemJs加载失败'));
    }, 10000);
  });
}
export function loadSystemjsImportmap(config: SceneViewerConfig): Promise<void> {
  if (!config.imports) {
    return Promise.resolve();
  }
  const map = { imports: {} };
  for (const item of Object.keys(config.imports)) {
    map.imports[item] = combinPath(config.serverPath, config.imports[item]);
  }
  const scriptText = JSON.stringify(map);

  return loadScript(undefined, 'systemjs-importmap', scriptText);
}

export function combinPath(serverPath: string, path?: string): string {
  if (!path) {
    return path ?? '';
  }

  return path.replace('${serverPath}', serverPath ?? '');
}

export function merge(source: SceneViewerConfig, target: SceneViewerConfig): SceneViewerConfig {
  const config:any = cloneObject(source);

  for (const item of Object.keys(target)) {
    if (config[item] === undefined) {
      continue;
    }
    if (typeof config[item] === 'object') {
      if (target[item] === null) {
        config[item] = null;
        continue;
      }
      if (config[item] === null) {
        config[item] = {};
      }

      merge(config[item], target[item]);
    } else {
      if (typeof target[item] === 'object') {
        config[item] = cloneObject(target[item]);
      } else {
        config[item] = target[item];
      }
    }
  }

  return config;
}

export function cloneObject<T = unknown>(config: T): T {
  if (config === undefined || config === null) {
    return config;
  }
  const newConfig = {};
  for (const item of Object.keys(config)) {
    if (config[item] === undefined) {
      continue;
    }
    if (typeof config[item] === 'object') {
      newConfig[item] = cloneObject(config[item]);
    } else {
      newConfig[item] = config[item];
    }
  }
  return newConfig as T;
}
